#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <queue>
#include <any>

#include <typeinfo>
#include <functional>
#include "assert.h"
#include <type_traits>

/*
   支持不同类型的可调用对象
  注册一个处理程序，它可以是以下之一:

 free functions
 lambdas
 function objects
 std::function objects
*/

struct Color {
    int r;
    int g;
    int b;
};

struct Message {
    enum class Id {
        SET_STATE = 0,
        SET_INTENSITY,
        SET_COLOR,
        TERMINATE
    };
    union Params {
        Color rgb;
        uint8_t intensity;
        bool state;
    };

    Id id;
    Params params;
};

std::condition_variable cv;
std::mutex m;
std::queue<Message> msg_queue;


struct CallbackWrapper {
    template <typename T>
    CallbackWrapper(T&& obj) :
        wrappedCallback(std::make_unique<Wrapper<typename std::remove_reference<T>::type>>
                        (std::forward<T>(obj))) { }

    struct CallbackBase {
        virtual bool operator()(const std::type_info& type) const = 0;
        virtual void operator()(const std::any& data) = 0;
        virtual ~CallbackBase() {}
    };

    template<typename T>
    struct Wrapper : public CallbackBase {

        typedef function_traits<T>::template arg<0> arg_type;

        Wrapper(const T& t) :
            wrappedObject(t) {}

        bool operator()(const std::type_info& type) const override {
            if (typeid(arg_type) == type) {
                return true;
            } else {
                return false;
            }
        }

        void operator()(const std::any& data) override {
            wrappedObject(std::any_cast<arg_type>(data));
        }

        T wrappedObject;
    };

    bool operator()(const std::type_info& type) {
        return (*wrappedCallback)(type);
    }

    void operator()(const std::any& data) {
        return (*wrappedCallback)(data);
    }

    std::unique_ptr<CallbackBase> wrappedCallback;
};


class Receiver {
public:
    void Run() {
        t = std::thread(&Receiver::Consume, this);
    }

    void Join() {
        if (t.joinable()) {
            t.join();
        }
    }

    template <typename Callback>
    void Handle(Callback cb) {
        static_assert(function_traits<Callback>::arity == 1, "Only one argument is supported");
        callbackWrappers.emplace_back(cb);
    }

private:
    std::thread t;
    std::vector<CallbackWrapper> callbackWrappers;

    std::any GetMessage() {
        std::any message;
        std::unique_lock<std::mutex> lock(m);
        
        cv.wait(lock, [](){return not msg_queue.empty();});
        message = msg_queue.front();
        msg_queue.pop();

        return message;
    }

    void Consume() {
        while (true) {
            const std::any msg = GetMessage();
            for (CallbackWrapper& callbackWrapper : callbackWrappers) {
                if (callbackWrapper(msg.type())) {
                    callbackWrapper(msg);
                }
            }
        }
    }
};


int main() {
    Receiver receiver;

    receiver.Handle([](const bool state) {
        std::cout << "SetState " << state << "\n";
    });
    receiver.Handle([](const uint8_t intensity) {
        std::cout << "SetIntensity " << (unsigned int) intensity << "\n";
    });
    receiver.Handle([](const Color& color) {
        std::cout << "SetColor " << color.r << ", " << color.g << ", " << color.b << "\n";
    });
    receiver.Run();
    receiver.Join();
}
